package com.bringspring.system.base.controller;

import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.fastjson.JSONObject;
import com.bringspring.common.base.ActionResult;
import com.bringspring.common.base.ActionResultCode;
import com.bringspring.common.base.NoDataSourceBind;
import com.bringspring.common.base.vo.DownloadVO;
import com.bringspring.common.base.vo.ListVO;
import com.bringspring.common.base.vo.PageListVO;
import com.bringspring.common.base.vo.PaginationVO;
import com.bringspring.common.config.ConfigValueUtil;
import com.bringspring.common.constant.MsgCode;
import com.bringspring.common.database.data.DataSourceContextHolder;
import com.bringspring.common.exception.DataException;
import com.bringspring.common.util.*;
import com.bringspring.common.util.enums.DictionaryDataEnum;
import com.bringspring.common.util.enums.ModuleTypeEnum;
import com.bringspring.common.util.file.FileExport;
import com.bringspring.common.util.treeutil.SumTree;
import com.bringspring.common.util.treeutil.newtreeutil.TreeDotUtils;
import com.bringspring.common.util.wxutil.HttpUtil;
import com.bringspring.system.base.entity.DataInterfaceEntity;
import com.bringspring.system.base.entity.DictionaryDataEntity;
import com.bringspring.system.base.model.dataInterface.*;
import com.bringspring.system.base.service.DataInterfaceService;
import com.bringspring.system.base.service.DictionaryDataService;
import com.bringspring.system.base.util.DbSensitiveConstant;
import com.bringspring.system.base.util.JsonUtilEx;
import com.bringspring.system.base.util.Props;
import com.bringspring.system.permission.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.util.*;


/**
 * 数据接口管理控制器
 *
 * @author 开发平台组
 * @version V1.0.0
 * @copyright 股份有限公司
 * @date 2021/3/12 15:31
 */
@Api(tags = "数据接口", value = "DataInterface")
@RestController
@RequestMapping(value = "/api/system/DataInterface")
public class DataInterfaceController {
    @Autowired
    private DataInterfaceService dataInterfaceService;
    @Autowired
    private UserService userService;
    @Autowired
    private DictionaryDataService dictionaryDataService;
    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private FileExport fileExport;
    @Autowired
    private UserProvider userProvider;
    @Autowired
    private Props props;

    /**
     * 获取接口列表(分页)
     *
     * @param pagination 分页参数
     * @return ignore
     */
    @ApiOperation("获取接口列表(分页)")
    @GetMapping
    public ActionResult<PageListVO<DataInterfaceListVO>> getList(PaginationDataInterface pagination) {
        List<DataInterfaceEntity> data = dataInterfaceService.getList(pagination, null);

        List<DataInterfaceListVO> list = JsonUtil.getJsonToList(data, DataInterfaceListVO.class);
        // 添加tenantId字段
        for (DataInterfaceListVO vo : list) {
            if (StringUtils.isNotEmpty(userProvider.get().getTenantId())) {
                vo.setTenantId(userProvider.get().getTenantId());
            }
            // 类别转换
            if ("1".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("增加");
            } else if ("2".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("修改");
            } else if ("3".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("查询");
            } else if ("4".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("删除");
            } else if ("5".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("存储");
            } else if ("6".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("GET");
            } else if ("7".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("POST");
            }
        }
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(list, paginationVO);
    }

    /**
     * 获取接口列表(工作流选择时调用)
     *
     * @param pagination 分页参数
     * @return ignore
     */
    @ApiOperation("获取接口列表(工作流选择时调用)")
    @GetMapping("/getList")
    public ActionResult<PageListVO<DataInterfaceGetListVO>> getLists(PaginationDataInterfaceModel pagination) {
        List<DataInterfaceEntity> data = dataInterfaceService.getList(pagination, pagination.getDataType());
        List<DataInterfaceGetListVO> list = JsonUtil.getJsonToList(data, DataInterfaceGetListVO.class);
        for (DataInterfaceGetListVO vo : list) {
            // 类别转换
            if ("1".equals(vo.getDataType())) {
                vo.setDataType("SQL操作");
            } else if ("2".equals(vo.getDataType())) {
                vo.setDataType("静态数据");
            } else if ("3".equals(vo.getDataType())) {
                vo.setDataType("Api数据");
            }
            // 类别转换
            if ("1".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("增加");
            } else if ("2".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("修改");
            } else if ("3".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("查询");
            } else if ("4".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("删除");
            } else if ("5".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("存储");
            } else if ("6".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("GET");
            } else if ("7".equals(vo.getRequestMethod())) {
                vo.setRequestMethod("POST");
            }
        }
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(list, paginationVO);
    }

    /**
     * 获取接口列表下拉框
     *
     * @return ignore
     */
    @ApiOperation("获取接口列表下拉框")
    @GetMapping("/GetParam/{id}")
    public ActionResult getSelector(@PathVariable("id") String id) {
        DataInterfaceEntity info = dataInterfaceService.getInfo(id);
        if (info!=null) {
            String requestParameters = info.getRequestParameters();
            List<DataInterfaceModel> jsonToList = JsonUtil.getJsonToList(requestParameters, DataInterfaceModel.class);
            return ActionResult.success(jsonToList == null ? new ArrayList<>() : jsonToList);
        }
        return ActionResult.fail("数据不存在");
    }

    /**
     * 获取接口列表下拉框
     *
     * @return ignore
     */
    @ApiOperation("获取接口列表下拉框")
    @GetMapping("/Selector")
    public ActionResult<List<DataInterfaceTreeVO>> getSelector() {
        List<DataInterfaceTreeModel> tree = new ArrayList<>();
        List<DataInterfaceEntity> data = dataInterfaceService.getList();
        List<DictionaryDataEntity> dataEntityList = dictionaryDataService.getList(DictionaryDataEnum.SYSTEM_DATAINTERFACE.getDictionaryTypeId());
        // 获取数据接口外层菜单
        for (DictionaryDataEntity dictionaryDataEntity : dataEntityList) {
            DataInterfaceTreeModel firstModel = JsonUtil.getJsonToBean(dictionaryDataEntity, DataInterfaceTreeModel.class);
            firstModel.setId(dictionaryDataEntity.getId());
            firstModel.setCategoryId("0");
            long num = data.stream().filter(t -> t.getCategoryId().equals(dictionaryDataEntity.getId())).count();
            if (num > 0) {
                tree.add(firstModel);
            }
        }
        for (DataInterfaceEntity entity : data) {
            DataInterfaceTreeModel treeModel = JsonUtil.getJsonToBean(entity, DataInterfaceTreeModel.class);
            treeModel.setCategoryId("1");
            treeModel.setParentId(entity.getCategoryId());
            treeModel.setId(entity.getId());
            DictionaryDataEntity dataEntity = dictionaryDataService.getInfo(entity.getCategoryId());
            if (dataEntity != null) {
                tree.add(treeModel);
            }
        }
        List<SumTree<DataInterfaceTreeModel>> sumTrees = TreeDotUtils.convertListToTreeDot(tree);
        List<DataInterfaceTreeVO> list = JsonUtil.getJsonToList(sumTrees, DataInterfaceTreeVO.class);
        ListVO<DataInterfaceTreeVO> vo = new ListVO<>();
        vo.setList(list);
        return ActionResult.success(list);
    }

    /**
     * 获取接口数据
     *
     * @param id 主键
     * @return ignore
     */
    @ApiOperation("获取接口数据")
    @GetMapping("/{id}")
    public ActionResult<DataInterfaceVo> getInfo(@PathVariable("id") String id) throws DataException {
        DataInterfaceEntity entity = dataInterfaceService.getInfo(id);
        DataInterfaceVo vo = JsonUtilEx.getJsonToBeanEx(entity, DataInterfaceVo.class);
        if (vo.getCheckType() == null) {
            vo.setCheckType(0);
        }
        return ActionResult.success(vo);
    }

    /**
     * 添加接口
     *
     * @param dataInterfaceCrForm 添加数据接口模型
     * @return ignore
     */
    @ApiOperation("添加接口")
    @PostMapping
    public ActionResult create(@RequestBody @Valid DataInterfaceCrForm dataInterfaceCrForm) {
        DataInterfaceEntity entity = JsonUtil.getJsonToBean(dataInterfaceCrForm, DataInterfaceEntity.class);
        // 判断是否有敏感字
        String containsSensitive = containsSensitive(dataInterfaceCrForm.getQuery());
        if (StringUtils.isNotEmpty(containsSensitive)) {
            return ActionResult.fail(containsSensitive);
        }
        if (dataInterfaceService.isExistByFullName(entity.getFullName(), entity.getId())) {
            return ActionResult.fail(MsgCode.EXIST001.get());
        }
        if (dataInterfaceService.isExistByEnCode(entity.getEnCode(), entity.getId())) {
            return ActionResult.fail(MsgCode.EXIST002.get());
        }
        dataInterfaceService.create(entity);
        return ActionResult.success("接口创建成功");
    }

    /**
     * 判断是否有敏感字
     *
     * @param sql
     * @return
     */
    private String containsSensitive(String sql) {
        if (StringUtils.isNotEmpty(sql)) {
            String[] split = DbSensitiveConstant.SENSITIVE.split(",");
            SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, "mysql");
            String token = parser.getExprParser().getLexer().token().toString();
            for (String str : split) {
                boolean contains = token.contains(str.trim());
                if (contains) {
                    return str.trim();
                }
            }
        }
        return "";
    }

    /**
     * 修改接口
     *
     * @param dataInterfaceUpForm 修改数据接口模型
     * @param id                  主键
     * @return ignore
     */
    @ApiOperation("修改接口")
    @PutMapping("/{id}")
    public ActionResult update(@RequestBody @Valid DataInterfaceUpForm dataInterfaceUpForm, @PathVariable("id") String id) throws DataException {
        DataInterfaceEntity entity = JsonUtilEx.getJsonToBeanEx(dataInterfaceUpForm, DataInterfaceEntity.class);
        // 判断是否有敏感字
        String containsSensitive = containsSensitive(dataInterfaceUpForm.getQuery());
        if (StringUtils.isNotEmpty(containsSensitive)) {
            return ActionResult.fail(containsSensitive);
        }
        if (dataInterfaceService.isExistByFullName(entity.getFullName(), id)) {
            return ActionResult.fail(MsgCode.EXIST001.get());
        }
        if (dataInterfaceService.isExistByEnCode(entity.getEnCode(), id)) {
            return ActionResult.fail(MsgCode.EXIST002.get());
        }
        boolean flag = dataInterfaceService.update(entity, id);
        if (flag == false) {
            return ActionResult.fail(MsgCode.FA013.get());
        }
        return ActionResult.success(MsgCode.SU013.get());
    }

    /**
     * 删除接口
     *
     * @param id
     * @return
     */
    @ApiOperation("删除接口")
    @DeleteMapping("/{id}")
    public ActionResult delete(@PathVariable String id) {
        DataInterfaceEntity entity = dataInterfaceService.getInfo(id);
        if (entity != null) {
            dataInterfaceService.delete(entity);
            return ActionResult.success(MsgCode.SU003.get());
        }
        return ActionResult.fail(MsgCode.FA003.get());
    }

    /**
     * 更新接口状态
     *
     * @param id
     * @return
     */
    @ApiOperation("更新接口状态")
    @PutMapping("/{id}/Actions/State")
    public ActionResult update(@PathVariable("id") String id) throws DataException {
        DataInterfaceEntity entity = dataInterfaceService.getInfo(id);
        if (entity != null) {
            if ("0".equals(String.valueOf(entity.getEnabledMark()))) {
                entity.setEnabledMark(1);
            } else {
                entity.setEnabledMark(0);
            }
            dataInterfaceService.update(entity, id);
            return ActionResult.success(MsgCode.SU014.get());
        }
        return ActionResult.fail(MsgCode.FA014.get());
    }

    /**
     * 获取接口分页数据
     *
     * @param id
     * @return
     */
    @ApiOperation("获取接口分页数据")
    @GetMapping("/{id}/Action/List")
    public ActionResult list(@PathVariable("id") String id, DataInterfacePage page) {
        ActionResult result = dataInterfaceService.infoToIdPageList(id, page);
        return result;
    }

    /**
     * 获取接口详情数据
     *
     * @param id
     * @return
     */
    @ApiOperation("获取接口详情数据")
    @GetMapping("/{id}/Action/Info")
    public ActionResult info(@PathVariable("id") String id, DataInterfacePage page) {
        Map<String, Object> data = dataInterfaceService.infoToInfo(id, page);
        return ActionResult.success(data);
    }

    /**
     * 预览
     *
     * @param id
     * @return
     */
    @ApiOperation("预览")
    @GetMapping("/{id}/Preview")
    public ActionResult Actions(@PathVariable("id") String id) {
        String escape = XSSEscape.escape(id);
        Object preview = dataInterfaceService.preview(escape);
        if (preview instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) preview;
            if (Objects.nonNull(jsonObject) && "1".equals(jsonObject.get("errorCode"))) {
                return ActionResult.fail(String.valueOf(jsonObject.get("errorMsg")));
            }
        }
        return ActionResult.success(preview);
    }

    /**
     * 测试接口
     *
     * @param id
     * @return
     */
    @ApiOperation("测试接口")
    @PostMapping("/{id}/Actions/Preview")
    @NoDataSourceBind
    public ActionResult callPreview(@PathVariable("id") String id, @RequestBody DataInterfaceParamModel model) {
        String name = null;
        if (Boolean.parseBoolean(configValueUtil.getMultiTenancy())) {
            // 判断是不是从外面直接请求
            if (StringUtils.isNotEmpty(model.getTenantId())) {
                //切换成租户库
                JSONObject object = HttpUtil.httpRequest(props.getPortUrl() + model.getTenantId(), "GET", null);
                if (object == null || StringUtils.isEmpty(object.getString("data"))) {
                    return ActionResult.fail(ActionResultCode.SessionOverdue.getMessage());
                }
                Map<String, Object> resulList = JsonUtil.stringToMap(object.getString("data"));
                name = resulList.get("java") != null ? String.valueOf(resulList.get("java")) : String.valueOf(resulList.get("dbName"));
                DataSourceContextHolder.setDatasource(model.getTenantId(), name);
            } else {
                if (Objects.isNull(userProvider.get())) {
                    return ActionResult.fail(ActionResultCode.SessionOverdue.getMessage());
                }
                DataSourceContextHolder.setDatasource(userProvider.get().getTenantId(), userProvider.get().getTenantDbConnectionString());
            }
        }
        Map<String, String> map = new HashMap<>(model.getParamList().size());
        List<DataInterfaceModel> jsonToList = JsonUtil.getJsonToList(model.getParamList(), DataInterfaceModel.class);
        for (DataInterfaceModel dataInterfaceModel : jsonToList) {
            map.put(dataInterfaceModel.getField(), dataInterfaceModel.getDefaultValue());
        }
        ActionResult actionResult = dataInterfaceService.infoToId(id, name, map);
        if (actionResult.getCode() == 200) {
            actionResult.setMsg("接口请求成功");
        }
        return actionResult;
    }

    /**
     * 数据接口导出功能
     *
     * @param id 接口id
     */
    @ApiOperation("导出数据接口数据")
    @GetMapping("/{id}/Action/Export")
    public ActionResult exportFile(@PathVariable("id") String id) {
        DataInterfaceEntity entity = dataInterfaceService.getInfo(id);
        DataInterfaceExport dataInterfaceExport = JsonUtil.getJsonToBean(entity, DataInterfaceExport.class);
        //导出文件
        DownloadVO downloadVO = fileExport.exportFile(dataInterfaceExport, configValueUtil.getTemporaryFilePath(), entity.getFullName(), ModuleTypeEnum.SYSTEM_DATAINTEFASE.getTableName());
        return ActionResult.success(downloadVO);
    }

    /**
     * 数据接口导入功能
     *
     * @param multipartFile
     * @return
     * @throws DataException
     */
    @ApiOperation("数据接口导入功能")
    @PostMapping(value = "/Action/Import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ActionResult importFile(@RequestPart("file") MultipartFile multipartFile) throws DataException {
        //判断是否为.json结尾
        if (FileUtil.existsSuffix(multipartFile, ModuleTypeEnum.SYSTEM_DATAINTEFASE.getTableName())) {
            return ActionResult.fail(MsgCode.IMP002.get());
        }
        //读取文件内容
        String fileContent = FileUtil.getFileContent(multipartFile, configValueUtil.getTemporaryFilePath());
        try {
            DataInterfaceEntity entity = JsonUtil.getJsonToBean(fileContent, DataInterfaceEntity.class);
            //id为空切名称不存在时
            if (dictionaryDataService.getInfo(entity.getCategoryId()) == null) {
                return ActionResult.fail(MsgCode.IMP004.get());
            }
            if (dataInterfaceService.getInfo(entity.getId()) == null &&
                    !dataInterfaceService.isExistByFullName(entity.getFullName(), entity.getId()) &&
                    !dataInterfaceService.isExistByEnCode(entity.getEnCode(), entity.getId())) {
                dataInterfaceService.create(entity);
                return ActionResult.success(MsgCode.IMP001.get());
            }

        } catch (Exception e) {
            throw new DataException(MsgCode.IMP004.get());
        }
        return ActionResult.fail(MsgCode.IMP003.get());
    }

}
